/*-+-*****************************************************************************
 Copyright (C) 2009-2012 Oceanside Software Corporation (R)
 Dallas, Texas

 Author       : Jason T. Brower
 Purpose      : This file is part of a point-of-sale software package
                originally written for Table-Service Restaurants.
              
 Date         : July 8th of 2012
              
 History      : The application that this software file belongs to was 
                written over a 3-Year period.  The first version was written
                in C# .Net 3.5 using Windows Forms.  Being new to .Net at
                the time, I soon learned of Windows Presentation Foundation,
                liked the graphics capabilities and databinding so I
                migrated to WPF.  When the .Net 4.0 framework was released
                the application was migrated from 3.5 to 4.0. Now today,
                .Net 4.5 RC is out and I was already in process of migrating
                before I made this public.
                
Excuse Me     : Please excuse the coding style, it is not representative of
                my typical work.  During the three years I was under a very
                tight budget, constantly running out of funding and was 
                working 18 hour days hyped up on 5-Hour Energy.  The 
                design is not textbook.  It is monolythic because of
                previous issues I will not get into.  There are few comments
                in the code and the ones that are there may be incorrect.
                
What it is not: This is not the exact version that I took through PA-DSS 2.0
                nor is it the exact version running at my customer sites.
                I removed some details for security purposes including some
                encryption algorithms.  The reporting was removed because
                I was including a third party library that cannot be 
                published with this Open Source.
                
What it is    : This application has been running at high volume restaraunts
                for over a year.  It never freezes, crashes or does anything
                unexpected.  So long as it is built, installed and configured
                correctly, it is a strong system that we can all enhance.

Contact       : Please note that I can no longer work for free.  However, you
                can reach me at information@oceansidesw.com.                                                      

*********************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
#if _LOCALDB
  using Oceanside.LocalDB;
#else
using Oceanside.RemoteDB;
#endif
namespace Oceanside
{
    static class TSBindings
    {
        private static bool _isWaitingForManagerSwipe = false;
        private static bool _isWaitingForPasswordSwipe = false;

        /// <summary>
        /// 
        /// </summary>
        public static void Init()
        {
            ///Handler for the cancel button
            Oceanside.TimeSheetWindow.ExitButton.MouseDown += new MouseButtonEventHandler(buttonBackLock_MouseDown_NOTHROW);
            Oceanside.TimeSheetWindow.ClockOutButton.MouseDown += new MouseButtonEventHandler(buttonClockOut_MouseDown_NOTHROW);
            Oceanside.TimeSheetWindow.StartBreakButton.MouseDown += new MouseButtonEventHandler(StartBreakButton_MouseDown);
            Oceanside.TimeSheetWindow.EndBreakButton.MouseDown += new MouseButtonEventHandler(EndBreakButton_MouseDown);

            Splasher.UpdateSplashStatus_NOTHROW("Initialize User Role Entries");
            ///Add four buttons as a user can have a max of four roles.
            foreach (Control control in Oceanside.TimeSheetWindow.PanelRoles.Children)
            {
                Button_155_58_Role ci = (Button_155_58_Role)control;
                ci.ButtonDownDelegate += new Oceanside.Button_155_58_Role.FunctionButtonDownDelegate(Role_Click_NOTHROW);
            }
        }

        static void EndBreakButton_MouseDown(object sender, MouseButtonEventArgs e)
        {
            try
            {
                var q = from B in SHIFT.Current.TIMESLIP.BREAKS where B.BreakStop == null select B;
                if (q.Any())
                {
                    BREAK b = q.First();
                    b.BreakStop = DateTime.Now;
                    SHIFT.Current.IsOnBreak = false;
                    SHIFT.GlobalContext.SaveChanges();
                    TSBindings.FireSessionPropertyChangedThreadSafe();
                }
            }
            catch (Exception exc)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PLACEHOLDER, exc);
            }
        }

        static void StartBreakButton_MouseDown(object sender, MouseButtonEventArgs e)
        {
            try
            {
                BREAK b = new BREAK();
                b.BreakStart = DateTime.Now;
                SHIFT.Current.TIMESLIP.BREAKS.Add(b);
                SHIFT.Current.IsOnBreak = true;
                SHIFT.GlobalContext.SaveChanges();
                TSBindings.FireSessionPropertyChangedThreadSafe();
            }
            catch (Exception exc)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PLACEHOLDER, exc);
            }
        }


        /// <summary>
        /// 
        /// </summary>
        private static void DisplayUsersRoles()
        {
            if (SHIFT.Current != null)
            {
                USER user = SHIFT.Current.User;

                StackPanel spRoles = Oceanside.TimeSheetWindow.PanelRoles;
                var q = from ROLE in user.ROLES where ROLE.IsDeleted == false select ROLE;
                if (q.Count() != 0)
                {
                    List<ROLE> userRoles = q.ToList();
                    int i = 0;
                    for (i = 0; i < userRoles.Count && i < spRoles.Children.Count; i++)
                    {
                        ROLE role = userRoles[i];
                        Button_155_58_Role rb = spRoles.Children[i] as Button_155_58_Role;
                        rb.Visibility = System.Windows.Visibility.Visible;
                        rb.ButtonLabelText = role.Name;
                        rb.DataContext = role;
                    }

                    while (i < spRoles.Children.Count)
                    {
                        spRoles.Children[i].Visibility = System.Windows.Visibility.Hidden;
                        i++;
                    }
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void buttonClockOut_MouseDown_NOTHROW(object sender, MouseButtonEventArgs e)
        {
            try
            {
                SHIFT.GlobalContext.SaveChanges();
                App.CashMoneyWindowInstance.ShowMe(0, CashMoneyBox.CashBoxType.TYPE_TIPS);
                if (CashMoneyBox.LastResponse == UserResponse.ENTER)
                {
                    App.InvokeStartStoryBoard_NOTHROW();
                    System.Threading.Tasks.Task.Factory.StartNew(() => CheckoutEmployee(SHIFT.Current.Id, CashMoneyBox.TotalAmount));
                }
            }
            catch (Exception exc)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_TSBIND_CLOCKOUT_CLICK, exc);
            }

        }

        /// <summary>
        /// 
        /// </summary>
        private static void CheckoutEmployee(Int64 shiftId, decimal cashTipsClaimed)
        {
            try
            {
                SHIFT.GlobalContext.SaveChanges();
                using (DominicaEntities context = new DominicaEntities(DominicaEntities.GetEfConString()))
                {
                    SHIFT shift = context.SHIFTS.Where(s => s.Id == shiftId).FirstOrDefault();

                    ///Cycle through and assure that this employee does not have any orders that 
                    ///are still open and need to be closed out.
                    bool hasOpenOrders = false;
                    foreach (ORDER order in shift.ORDERS.ToList())
                    {
                        if (order.SALES.Count == 0 && order.TRANSACTIONS.Count == 0)
                        {
                            shift.ORDERS.Remove(order);
                        }
                        else if (!order.IsClosed)
                        {
                            hasOpenOrders = true;
                            break;
                        }
                    }
                    context.SaveChanges();
                    if (!hasOpenOrders)
                    {
                        SHIFT.CloseShift(context, shift, cashTipsClaimed, false);
                        KIOSK k = KIOSK.Get(context);
                        if (k.LocalPrinterId != null && k.LocalPrinterId != 0)
                        {
                            string path = context.PRINTERS.Where(p => p.Id == k.LocalPrinterId).FirstOrDefault().Path;
                            SHIFT.SHIFT_CHECKOUTDATA scd = SHIFT.GenerateCheckoutData(shift, context, false);
                            SYSCONFIG sysconfig = SYSCONFIG.Get(context);


                            ///HACK -- The IncludeDiscountsInNetSales field was not being used and we needed to quickly find
                            ///a way to enable or disable the printing of an employee checkout that did not have any sales.
                            ///This is what that field is used for and will be updated in the next db release.
                            if (scd.totalSales != 0 || sysconfig.IncludeDiscountsInNetSales)
                            {
                                PrintSpool.PrintCheckout(path, scd);
                            }
                        }
                        App.InvokeStopStoryBoard_NOTHROW();
                        Constants.MainDispatcher.BeginInvoke(new Action(()=> Oceanside.LoginWindow.Show()));
                    }
                    else
                    {
                        String tableOrOrder = Constants.IsQuickServiceMode ? "order(s)" : "table(s)";

                        UMD.ShowGuiMessageSTASafe_NOTHROW("There are still open " + tableOrOrder +
                            " that are listed under your username.  You cannot checkout until you transfer or close those "
                            + tableOrOrder + ".");
                    }
                }
            }
            catch (Exception exc)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_LVBIND_CALL_CASHIER_CHECKOUT, exc);
                App.InvokeStopStoryBoard_NOTHROW();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        static void Role_Click_NOTHROW(object sender, MouseButtonEventArgs e)
        {
            try
            {
                Button_155_58_Role ci = sender as Button_155_58_Role;

                if (ci != null && ci.DataContext != null)
                {
                    ROLE role = ci.DataContext as ROLE;
                    ClockIn_NOTHROW(role);
                }
            }
            catch (Exception exc)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_TSBIND_ROLE_CLICK, exc);
            }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="selectedRole"></param>
        static void ClockIn_NOTHROW(ROLE selectedRole)
        {
            try
            {
                SHIFT shift = SHIFT.Current;
                DAYPART daypart = DAYPART.GetCurrDaypart(SHIFT.GlobalContext);

                ///If their shift object does not exist, then add it.
                if (shift == null)
                {
                    shift = new SHIFT();
                    shift.DateStamp = DateTime.Now;
                    shift.UserId = shift.User.Id;
                    SHIFT.GlobalContext.SaveChanges();
                }

                if (shift.TimePunch == null)
                {
                    TIMESLIP tp = new TIMESLIP();
                    tp.SHIFT = shift;
                    tp.UserId = shift.User.Id;
                    tp.ClockedIn = DateTime.Now;
                    tp.ClockedInDaypartId = daypart.Id;
                    tp.ClockedInKioskId = KIOSK.Get(SHIFT.GlobalContext).Id;
                    tp.RoleId = selectedRole.Id;
                    tp.RevenueCenterId = KIOSK.Get(SHIFT.GlobalContext).RevenueCenterId;
                    SHIFT.GlobalContext.SaveChanges();
                    shift.IsClockedIn = true;
                    SHIFT.GlobalContext.SaveChanges();
                }

                ///This should never be hit, but in rare DB cases, it might happen.
                if (shift.TimePunch.RoleId == 0)
                {
                    shift.TimePunch.RoleId = selectedRole.Id;
                    shift.IsClockedIn = true;
                    SHIFT.GlobalContext.SaveChanges();
                }
            }
            catch (System.Exception exc)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_PTIMEPUNCH_ADD_TIMEPUNCH, exc);

                try
                {
                    Button_155_58_Role.UnHilightAllThreadSafe();
                }
                catch (Exception e)
                {
                    Logging.LogException(e);
                }
            }
            finally
            {
                try
                {
                    TSBindings.FireSessionPropertyChangedThreadSafe();
                    PosWindow.RefreshVisibility(PosWindow.PROP_TYPE_ENUM.TS);
                }
                catch (Exception ex)
                {
                    Logging.LogException(ex);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void FireSessionPropertyChangedThreadSafe()
        {
            if (PosWindow.MainPosWindow.Dispatcher.CheckAccess())
            {
                SHIFT.Current.OnPropertyChanged(new System.ComponentModel.PropertyChangedEventArgs(""));
            }
            else
            {
                PosWindow.MainPosWindow.Dispatcher.Invoke(new Action(FireSessionPropertyChangedThreadSafe));
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void ClaimDrawerClicked(int intDrawer)
        {
            App.CashMoneyWindowInstance.ShowMe(0, CashMoneyBox.CashBoxType.TYPE_CLAIM_DRAWER);

            if (CashMoneyBox.LastResponse == UserResponse.ENTER)
            {
                SHIFT.DrawerOwnershipEnum drawer;
                if (intDrawer == 2)
                {
                    drawer = SHIFT.DrawerOwnershipEnum.Drawer2;
                }
                else
                {
                    drawer = SHIFT.DrawerOwnershipEnum.Drawer1;
                }

                SHIFT.Current.AddAsDrawerOwner(drawer);

                if (SHIFT.Current.DrawerStart != 0)
                {
                    UMD.ShowGuiMessageSTASafe_NOTHROW("Please note that you have previously claimed a drawer and the amount of " + CashMoneyBox.TotalAmount.ToString("c") + " will be added to your existing drawer claim of " + SHIFT.Current.DrawerStart.ToString("c") + ".");

                }
                SHIFT.Current.DrawerStart += CashMoneyBox.TotalAmount;
                SHIFT.GlobalContext.SaveChanges();
                FireSessionPropertyChangedThreadSafe();
                PosWindow.RefreshVisibility(PosWindow.PROP_TYPE_ENUM.TS);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void ReleaseDrawerClicked(SHIFT.DrawerOwnershipEnum drawer)
        {
            YesNoBox ynb = new YesNoBox();
            SHIFT session = SHIFT.GetDrawerOwnerSession(drawer);
            if (session != null)
            {
                USER user = USER.GetUserById(session.UserId);
                if (user != null)
                {
                    ynb.SetMessage("Are you certain you want to release the drawer locked by user " + user.FirstName + " " + user.LastName + ".");
                    ynb.ShowDialog();
                    if (YesNoBox.LastResponse == UserResponse.YES)
                    {
                        SHIFT.RemoveAsDrawerOwner(drawer);
                        SHIFT.GlobalContext.SaveChanges();
                        FireSessionPropertyChangedThreadSafe();
                        PosWindow.RefreshVisibility(PosWindow.PROP_TYPE_ENUM.TS);
                    }
                }
            }
        }

        private static void RefreshSelectedRole()
        {
            Panel panel = Oceanside.TimeSheetWindow.PanelRoles;
            foreach (Button_155_58_Role button in panel.Children)
            {
                ROLE role = button.DataContext as ROLE;
                if (role != null &&
                    SHIFT.Current.Role != null &&
                    SHIFT.Current.Role.Id == role.Id)
                {
                    button.HighlightNew();
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void PrepareForScreenChange_NOTHROW()
        {
            try
            {
                Oceanside.TimeSheetWindow.AssignDataContext(SHIFT.Current);

                DisplayUsersRoles();
                Button_155_58_Role.UnHilightAllThreadSafe();

                RefreshSelectedRole();
                FireSessionPropertyChangedThreadSafe();
                PosWindow.RefreshVisibility(PosWindow.PROP_TYPE_ENUM.TS);
                ResetMagStripePasswordFlags();
            }
            catch (Exception exc)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_TSBIND_PREPARE_FOR_SCREEN_CHANGE, exc);
            }
        }





        /// <summary>
        /// 
        /// </summary>
        /// <param Name="sender"></param>
        /// <param Name="e"></param>
        static void buttonBackLock_MouseDown_NOTHROW(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            try
            {
                if (SHIFT.Current.IsClockedIn && !SHIFT.Current.IsOnBreak && SHIFT.Current.UserCanOrder())
                {
                    ControlPanelWindow.Show();
                }
                else
                {
                    LoginWindow.Show();
                }
            }
            catch (Exception exc)
            {
                Constants.ErrorDispatcher.Notify(Error.EType.E_TSBIND_EXIT_BUTTON_CLICK, exc);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public static void SetPasswordClicked()
        {
            if (!SHIFT.Current.User.CanSetMagStripe())
            {
                AskForManager_Swipe();
            }
            else
            {
                AskForPasswordSwipe();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param Name="cardData"></param>
        public static void OceansideCardSwiped(String cardNumber)
        {
            if (_isWaitingForManagerSwipe)
            {
                USER user = USER.ValidatePassword(cardNumber, true);
                if (!user.CanSetMagStripe())
                {
                    UMD.ShowGuiMessageSTASafe_NOTHROW("I'm sorry, let's try again.  Please click 'OK' and swipe the magnetic card of a user who has such rights as configured by the back " +
                        "office control panel software.");
                }
                else
                {
                    _isWaitingForManagerSwipe = false;
                    _isWaitingForPasswordSwipe = true;
                    AskForPasswordSwipe();
                }
            }
            else if (_isWaitingForPasswordSwipe)
            {
                ResetMagStripePasswordFlags();

                USER remoteUser = null;

                try
                {
                    USER.ENUM_SET_MAG_PWORD_STATUS localStatus =
                        SHIFT.Current.User.SetPosSwipeLogin(cardNumber);
                    if (USER.ENUM_SET_MAG_PWORD_STATUS.SUCCESS == localStatus)
                    {
                        UMD.ShowGuiMessageSTASafe_NOTHROW("The password has been successfully set for "
                            + SHIFT.Current.User.FirstName + " " +
                            SHIFT.Current.User.LastName);
                    }
                    else if (USER.ENUM_SET_MAG_PWORD_STATUS.PWORD_CURR_IN_USE == localStatus)
                    {
                        String message = "That magnetic stripe password is already in use";
                        if (remoteUser != null)
                        {
                            message += " by " + remoteUser.FirstName + " " + remoteUser.LastName;
                        }
                        message += ".";
                        UMD.ShowGuiMessageSTASafe_NOTHROW(message);
                    }
                    else
                    {
                        UMD.ShowGuiMessageSTASafe_NOTHROW("A communication failure has occured and the system was unable to set the password in the local database.");
                    }
                }
                catch (Exception e)
                {
                    UMD.ShowGuiMessageSTASafe_NOTHROW("A communication failure has occured and the system was unable to set the password in the remote database.");
                    Logging.LogException(e);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        private static void ResetMagStripePasswordFlags()
        {
            _isWaitingForManagerSwipe = false;
            _isWaitingForPasswordSwipe = false;
        }

        /// <summary>
        /// 
        /// </summary>
        private static void AskForManager_Swipe()
        {
            UMD.ShowGuiMessageSTASafe_NOTHROW("This function requires special access rights.  Please click 'OK' and swipe the magnetic card of a user who has such rights as configured by the back " +
                "office control panel software.");
            _isWaitingForManagerSwipe = true;
            _isWaitingForPasswordSwipe = false;
        }

        /// <summary>
        /// 
        /// </summary>
        private static void AskForPasswordSwipe()
        {
            UMD.ShowGuiMessageSTASafe_NOTHROW("Please click ok, then swipe the magnetic card for " +
                SHIFT.Current.User.FirstName + " " +
                SHIFT.Current.User.LastName +
                " and wait for a confirmation dialog box.");
            _isWaitingForManagerSwipe = false;
            _isWaitingForPasswordSwipe = true;
        }
    }
}

